"""
HTTP客户端模块
"""

import json
import logging
import time
from abc import ABC, abstractmethod

import requests
import urllib3
from urllib3.exceptions import IncompleteRead, ProtocolError

from jlpay.exception.exceptions import HttpExecutionException, HttpStatusCodeException

# 创建日志记录器
logger = logging.getLogger("jlpay.http")

def configure_logging(level=logging.INFO, log_file=None):
    """
    配置HTTP模块的日志
    
    Args:
        level: 日志级别，默认为INFO
        log_file: 日志文件路径，默认为None（仅控制台输出）
    """
    # 设置日志级别
    logger.setLevel(level)
    
    # 如果logger已经有处理器，不再添加
    if logger.handlers:
        return
    
    # 创建格式化器
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    # 创建控制台处理器
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)
    
    # 如果指定了日志文件，创建文件处理器
    if log_file:
        file_handler = logging.FileHandler(log_file, encoding='utf-8')
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)
    
    # 设置为不向上传播，避免重复日志
    logger.propagate = False
    
    logger.info("HTTP日志配置初始化完成")

# 默认配置日志（应用程序可以在其他地方重新配置）
configure_logging()

class HttpClient(ABC):
    """HTTP客户端接口"""
    
    @abstractmethod
    def execute(self, request):
        """
        执行HTTP请求
        
        Args:
            request: HttpRequest对象
            
        Returns:
            HttpResponse对象
            
        Raises:
            HttpExecutionException: 执行异常
            HttpStatusCodeException: 状态码异常
        """
        pass


class HttpClientWrapper(HttpClient):
    """HTTP客户端实现类"""
    
    def __init__(self, connect_timeout=10000, read_timeout=30000, max_retries=3):
        """
        初始化HTTP客户端
        
        Args:
            connect_timeout: 连接超时时间，单位毫秒
            read_timeout: 读取超时时间，单位毫秒
            max_retries: 最大重试次数
        """
        self.connect_timeout = connect_timeout / 1000  # 转换为秒
        self.read_timeout = read_timeout / 1000  # 转换为秒
        self.max_retries = max_retries
    
    def execute(self, request):
        """
        执行HTTP请求
        
        Args:
            request: HttpRequest对象
            
        Returns:
            HttpResponse对象
            
        Raises:
            HttpExecutionException: 执行异常
            HttpStatusCodeException: 状态码异常
        """
        retry_count = 0
        last_exception = None
        
        while retry_count <= self.max_retries:
            try:
                headers = request.headers
                url = request.url
                method = request.method
                params = request.params
                body = request.body
                files = request.files
                
                # 记录请求开始日志
                logger.debug(f"发起HTTP请求: {method} {url}{' (重试 #'+str(retry_count)+')' if retry_count > 0 else ''}")
                logger.debug(f"请求头: {headers}")
                if params:
                    logger.debug(f"请求参数: {params}")
                if body:
                    logger.debug(f"请求体: {body}")
                
                start_time = time.time()
                
                # 设置请求参数
                kwargs = {
                    'headers': headers,
                    'timeout': (self.connect_timeout, self.read_timeout),
                }
                
                if params:
                    kwargs['params'] = params
                    
                if files:
                    kwargs['files'] = files
                elif body:
                    # 如果是字典，转换为JSON字符串
                    if isinstance(body, dict):
                        # 直接使用UTF-8编码的字节，不再转为latin1
                        kwargs['data'] = json.dumps(body, ensure_ascii=False).encode('utf-8')
                        # 确保Content-Type包含正确的charset
                        if 'Content-Type' in headers and 'application/json' in headers['Content-Type']:
                            if 'charset=' not in headers['Content-Type']:
                                headers['Content-Type'] = headers['Content-Type'] + '; charset=utf-8'
                    else:
                        kwargs['data'] = body
                
                # 发送请求
                response = None
                if method.upper() == 'GET':
                    response = requests.get(url, **kwargs)
                elif method.upper() == 'POST':
                    response = requests.post(url, **kwargs)
                
                # 计算请求耗时
                elapsed_time = (time.time() - start_time) * 1000  # 转换为毫秒
                
                # 记录响应日志
                logger.debug(f"HTTP响应状态码: {response.status_code}, 耗时: {elapsed_time:.2f}ms")
                logger.debug(f"响应头: {dict(response.headers)}")
                
                # 检查状态码
                if response.status_code != 200:
                    logger.error(f"HTTP响应异常状态码: {response.status_code}, 响应内容: {response.text}")
                    raise HttpStatusCodeException(response.status_code, response.text)
                
                # 记录响应体日志（仅在调试级别）
                logger.debug(f"响应体: {response.text}")
                
                # 构建响应对象
                http_response = HttpResponse()
                http_response.body = response.text
                http_response.status = response.status_code
                http_response.headers = dict(response.headers)
                
                return http_response
                
            except (IncompleteRead, ProtocolError, requests.exceptions.ChunkedEncodingError, 
                    requests.exceptions.ConnectionError, urllib3.exceptions.ReadTimeoutError,
                    requests.exceptions.ReadTimeout) as e:
                last_exception = e
                retry_count += 1
                if retry_count <= self.max_retries:
                    wait_time = 2 ** retry_count  # 指数退避策略
                    logger.warning(f"HTTP请求遇到连接错误: {str(e)}, 正在进行第 {retry_count} 次重试, 等待 {wait_time} 秒...")
                    time.sleep(wait_time)
                else:
                    logger.error(f"HTTP请求重试 {self.max_retries} 次后仍然失败: {str(e)}", exc_info=True)
                    raise HttpExecutionException(f"HTTP请求重试失败: {str(e)}", e)
            except HttpStatusCodeException:
                raise
            except Exception as e:
                last_exception = e
                logger.error(f"HTTP请求执行异常: {str(e)}", exc_info=True)
                raise HttpExecutionException(f"HTTP请求执行异常: {str(e)}", e)
        
        # 如果所有重试都失败了
        if last_exception:
            logger.error(f"HTTP请求重试 {self.max_retries} 次后仍然失败: {str(last_exception)}", exc_info=True)
            raise HttpExecutionException(f"HTTP请求重试失败: {str(last_exception)}", last_exception)


class DefaultHttpClientBuilder:
    """HTTP客户端构建器"""
    
    @staticmethod
    def build(connect_timeout=10000, read_timeout=30000, max_retries=3):
        """
        构建HTTP客户端
        
        Args:
            connect_timeout: 连接超时时间，单位毫秒
            read_timeout: 读取超时时间，单位毫秒
            max_retries: 最大重试次数，默认3次
            
        Returns:
            HttpClient实例
        """
        return HttpClientWrapper(connect_timeout, read_timeout, max_retries)


class HttpRequest:
    """HTTP请求类"""
    
    def __init__(self, builder):
        """
        从Builder创建HttpRequest实例
        
        Args:
            builder: HttpRequestBuilder实例
        """
        self.url = builder._url
        self.method = builder._method
        self.headers = builder._headers
        self.params = builder._params
        self.body = builder._body
        self.files = builder._files
    
    @staticmethod
    def builder():
        """返回一个新的HttpRequestBuilder实例"""
        return HttpRequest.HttpRequestBuilder()
    
    class HttpRequestBuilder:
        """HTTP请求构建器"""
        
        def __init__(self):
            """初始化Builder属性"""
            self._url = None
            self._method = "POST"  # 默认使用POST
            self._headers = {}
            self._params = None
            self._body = None
            self._files = None
        
        def url(self, url):
            """
            设置URL
            
            Args:
                url: 请求URL
                
            Returns:
                HttpRequestBuilder实例
            """
            self._url = url
            return self
        
        def method(self, method):
            """
            设置HTTP方法
            
            Args:
                method: HTTP方法
                
            Returns:
                HttpRequestBuilder实例
            """
            self._method = method
            return self
        
        def header(self, key, value):
            """
            添加请求头
            
            Args:
                key: 请求头名称
                value: 请求头值
                
            Returns:
                HttpRequestBuilder实例
            """
            self._headers[key] = value
            return self
        
        def params(self, params):
            """
            设置URL参数
            
            Args:
                params: URL参数字典
                
            Returns:
                HttpRequestBuilder实例
            """
            self._params = params
            return self
        
        def body(self, body):
            """
            设置请求体
            
            Args:
                body: 请求体，可以是字典或字符串
                
            Returns:
                HttpRequestBuilder实例
            """
            self._body = body
            return self
        
        def files(self, files):
            """
            设置上传文件
            
            Args:
                files: 文件字典
                
            Returns:
                HttpRequestBuilder实例
            """
            self._files = files
            return self
        
        def build(self):
            """
            构建HttpRequest实例
            
            Returns:
                HttpRequest实例
            """
            return HttpRequest(self)


class HttpResponse:
    """HTTP响应类"""
    
    def __init__(self):
        """初始化响应对象"""
        self.body = None
        self.status = None
        self.headers = {} 